/**
 * @Copyright:Copyright (c) 1992 - 2015
 * @Company: TengTong
 */
package com.tengtong.duang.commons.convert.support;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;

import com.tengtong.duang.commons.base.AssertUtils;
import com.tengtong.duang.commons.convert.ConditionalConverter;
import com.tengtong.duang.commons.convert.ConversionException;

/**
 * 日期转换类，本类实现将下面的类型转为日期类：
 * 
 *    1）String
 *    
 *    2）long
 *    
 *    3）timestamp
 *    
 *    4）java.sql.date
 * 
 * @author jai
 *
 */
public class DateGenericConverter implements ConditionalConverter{

	public static final String[] DEFAULT_DATETIME_PATTERNS = {
									"yyyy-MM-dd HH:mm:ss", 
									"yyyy/MM/dd HH:mm:ss", 
									"MM/dd/yyyy HH:mm:ss", 
									"yyyyMMddHHmmss",
									"yyyy-MM-dd",
									"yyyy/MM/dd",
									"MM/dd/yyyy",	
									"HH:mm:ss"};

	private static final Set<Class<?>> matchesClasses = new HashSet<Class<?>>(6){{
		add(Date.class);
		add(java.sql.Date.class);
		add(java.sql.Timestamp.class);
		add(Long.class);
		add(String.class);
	}};
	
	/**
	 * 支持的转换格式，主要是为 String --> Date 提供格式，可以有多个
	 */
	private String[] patterns = DEFAULT_DATETIME_PATTERNS;

	private Locale locale;

	private TimeZone timeZone;

	private boolean useLocaleFormat;
	
	/* (non-Javadoc)
	 * @see com.tengtong.duang.commons.convert.ConditionalConverter#matches(java.lang.Class, java.lang.Class)
	 */
	@Override
	public boolean matches(Class<?> sourceType, Class<?> targetType) {
		AssertUtils.notNull(sourceType, "sourceType 不能为 null.");
		AssertUtils.notNull(targetType, "targetType 不能为 null.");
		
		if(!Date.class.equals(targetType)){
			return false;
		}
		
		return matchesClasses.contains(sourceType);
	}

	/* (non-Javadoc)
	 * @see com.tengtong.duang.commons.convert.ConditionalConverter#convert(java.lang.Object, java.lang.Class)
	 */
	@Override
	public Object convert(Object source, Class targetType) {
        if(source != null && targetType != null && Date.class.equals(targetType)){
        	Class<?> sourceType = source.getClass();
        	
        	if(sourceType.equals(java.sql.Date.class)){
        		java.sql.Date d = (java.sql.Date)source;
        		return new Date(d.getTime());
        	}
        	
        	if(sourceType.equals(Long.class)){
        		return new Date(((Long)source).longValue());
        	}
        	
        	if(sourceType.equals(Timestamp.class)){
        		Timestamp tt = (Timestamp)source;
        		return new Date(tt.getTime());
        	}
        	
        	if(sourceType.equals(String.class)){
        		return stringToDate((String)source);
        	}
        	
        	if(sourceType.isAssignableFrom(Date.class))
        		return (Date)source;
        	
        }
		
		return null;
	}

	/**
	 * 将字符串转成日期
	 *
	 * @param source
	 * @return
	 */
	private Date stringToDate(String source){
        Exception firstEx = null;
        for (int i = 0; i < patterns.length; i++) {
            try {
                DateFormat format = getFormat(patterns[i]);
                //Calendar calendar = parse(sourceType, targetType, value, format);
                
                return format.parse(source);
            } catch (Exception ex) {
                if (firstEx == null) {
                    firstEx = ex;
                }
            }
        }
        if (patterns.length > 1) {
            throw new ConversionException("Error converting '" + source + "' to Date using  patterns ");
        } else {
            throw new ConversionException(String.class, Date.class, source, firstEx);
        }
	}

	private DateFormat getFormat(String pattern){
        DateFormat format = new SimpleDateFormat(pattern);
        if (timeZone != null) {
            format.setTimeZone(timeZone);
        }
        return format;
	}
	
    public void setUseLocaleFormat(boolean useLocaleFormat) {
        this.useLocaleFormat = useLocaleFormat;
    }

    public String getPattern(){
    	if(patterns != null && patterns.length > 1)
    		return patterns[0];
    	return null;
    }
    
    public void setPattern(String pattern){
    	if(pattern == null)
    		patterns = null;
   		patterns = new String[] { pattern };
    }
    
	public String[] getPatterns() {
		return patterns;
	}

	public void setPatterns(String[] patterns) {
		this.patterns = patterns;
	}

	public Locale getLocale() {
		return locale;
	}

	public void setLocale(Locale locale) {
		this.locale = locale;
		setUseLocaleFormat(true);
	}

	public TimeZone getTimeZone() {
		return timeZone;
	}

	public void setTimeZone(TimeZone timeZone) {
		this.timeZone = timeZone;
	}

}
